import math
from datetime import datetime, timedelta
from dataclasses import dataclass
from typing import Dict, List, Tuple

@dataclass
class BodyData:
    """用户身体数据"""
    height_cm: float
    weight_kg: float
    body_fat_percentage: float
    skeletal_muscle_kg: float
    age: int

@dataclass
class ExerciseData:
    """单个动作的训练数据"""
    name: str
    weight_kg: float
    sets: int
    reps: int

class MuscleRecoveryEstimator:
    """
    基于训练量和身体数据的肌肉恢复时间估算器
    """
    # 不同肌肉群的基础恢复时间（小时），代表完全恢复所需时间
    BASE_RECOVERY_HOURS = {
        "胸肌": 48, "背阔肌": 48, "三角肌": 72, "肱二头肌": 24, "肱三头肌": 24,
        "腹肌": 24, "股四头肌": 72, "腘绳肌": 72, "臀大肌": 72, "小腿肌群": 24
    }

    # 不同动作的目标肌肉群映射
    EXERCISE_MUSCLE_MAP = {
        "卧推": ["胸肌", "三角肌", "肱三头肌"],
        "俯卧撑": ["胸肌", "三角肌", "肱三头肌"],
        "引体向上": ["背阔肌", "肱二头肌"],
        "划船": ["背阔肌", "三角肌", "肱二头肌"],
        "深蹲": ["股四头肌", "臀大肌", "腘绳肌"],
        "硬拉": ["背阔肌", "腘绳肌", "臀大肌"],
        "卷腹": ["腹肌"],
        "平板支撑": ["腹肌", "三角肌"],
        "哑铃弯举": ["肱二头肌"],
        "哑铃推举": ["三角肌", "肱三头肌"],
        "坐姿划船": ["背阔肌", "肱二头肌"],
        "臀桥": ["臀大肌", "腘绳肌"]
    }

    def __init__(self):
        self.muscle_damage = {name: 0.0 for name in self.BASE_RECOVERY_HOURS}

    def calculate_volume(self, weight: float, sets: int, reps: int) -> float:
        """计算训练量 (重量 * 组数 * 次数)"""
        return weight * sets * reps

    def calculate_intensity_factor(self, weight: float, body_weight: float) -> float:
        """
        计算强度系数 (基于重量与体重的比例)
        假设以自身体重为基准1.0，每增加20%体重重量，强度系数增加0.1
        """
        ratio = weight / body_weight
        # 系数范围大致在 0.5 (轻量) 到 2.0 (大重量) 之间
        base_factor = 0.5
        intensity_factor = base_factor + (ratio - 1.0) * 0.5
        return max(0.5, min(2.0, intensity_factor)) # 限制范围

    def estimate_muscle_damage(
        self,
        exercise_data: List[ExerciseData],
        body_data: BodyData
    ) -> Dict[str, float]:
        """
        估算训练后的肌肉群损伤百分比
        """
        # 重置之前的损伤
        self.muscle_damage = {name: 0.0 for name in self.BASE_RECOVERY_HOURS}

        for exercise in exercise_data:
            if exercise.name not in self.EXERCISE_MUSCLE_MAP:
                print(f"警告: 未知的动作 '{exercise.name}'，已跳过。")
                continue

            target_muscles = self.EXERCISE_MUSCLE_MAP[exercise.name]
            volume = self.calculate_volume(exercise.weight_kg, exercise.sets, exercise.reps)
            intensity_factor = self.calculate_intensity_factor(exercise.weight_kg, body_data.weight_kg)

            # 基础损伤计算 (与体积和强度因子成正比)
            base_damage = volume * intensity_factor * 0.001 # 调整系数使结果合理

            # 根据身体数据进行调整
            # 肌肉量大、体脂低的人恢复能力可能稍强，但损伤也可能更大 (因为绝对训练量大)
            muscle_mass_factor = body_data.skeletal_muscle_kg / 30.0 # 以30kg为基准
            age_factor = max(0.8, 1.1 - (body_data.age - 20) * 0.005) # 年龄越大恢复越慢

            adjusted_damage = base_damage * muscle_mass_factor * age_factor

            for muscle in target_muscles:
                self.muscle_damage[muscle] += adjusted_damage

        # 将损伤值转换为百分比，假设100%对应一个特定的高损伤值
        # 这里设定一个最大预期损伤值，例如100代表接近极限的损伤
        max_expected_damage = 100.0
        for muscle, damage in self.muscle_damage.items():
            self.muscle_damage[muscle] = min(99.0, (damage / max_expected_damage) * 100.0) # 损伤不超过99%

        return self.muscle_damage

    def calculate_recovery_time(
        self,
        exercise_data: List[ExerciseData],
        body_data: BodyData
    ) -> Dict[str, timedelta]:
        """
        计算各肌肉群的恢复时间
        """
        damage_percentages = self.estimate_muscle_damage(exercise_data, body_data)
        recovery_times = {}

        for muscle, damage in damage_percentages.items():
            if damage <= 0:
                recovery_times[muscle] = timedelta(hours=0)
            else:
                base_hours = self.BASE_RECOVERY_HOURS[muscle]
                # 恢复时间与损伤百分比成正比
                hours = base_hours * (damage / 100.0)
                recovery_times[muscle] = timedelta(hours=hours)

        return recovery_times

    def print_recovery_summary(
        self,
        exercise_data: List[ExerciseData],
        body_data: BodyData
    ):
        """
        打印恢复时间摘要
        """
        print("\n--- 输入数据 ---")
        print(f"身高: {body_data.height_cm} cm")
        print(f"体重: {body_data.weight_kg} kg")
        print(f"体脂率: {body_data.body_fat_percentage}%")
        print(f"骨骼肌: {body_data.skeletal_muscle_kg} kg")
        print(f"年龄: {body_data.age} 岁")
        print("\n训练计划:")
        for ex in exercise_data:
            print(f"  - {ex.name}: {ex.weight_kg}kg x {ex.sets}组 x {ex.reps}次")

        print("\n--- 估算的肌肉群恢复时间 ---")
        recovery_times = self.calculate_recovery_time(exercise_data, body_data)
        now = datetime.now()
        
        # 按照恢复时间排序显示
        sorted_items = sorted(recovery_times.items(), key=lambda item: item[1], reverse=True)

        for muscle, time_delta in sorted_items:
            if time_delta.total_seconds() > 0:
                end_time = now + time_delta
                hours, remainder = divmod(int(time_delta.total_seconds()), 3600)
                minutes, _ = divmod(remainder, 60)
                formatted_time = f"{hours}小时 {minutes}分钟"
                print(f"{muscle:<10} | 损耗估算: {self.muscle_damage[muscle]:5.1f}% | 恢复时间: {formatted_time} | 预计恢复: {end_time.strftime('%Y-%m-%d %H:%M:%S')}")
            else:
                print(f"{muscle:<10} | 损耗估算: {self.muscle_damage[muscle]:5.1f}% | 恢复时间: 0小时 | 预计恢复: 无需恢复")


def main():
    estimator = MuscleRecoveryEstimator()

    print("欢迎使用基于训练量和身体数据的肌肉恢复时间估算器！")
    print("请注意：此估算仅供参考，实际恢复时间因人而异。")

    # 示例：卧推70kg 5*5，25岁男性，168cm/66kg/体脂16%/骨骼肌31.9kg
    example_body_data = BodyData(
        height_cm=168,
        weight_kg=66,
        body_fat_percentage=16,
        skeletal_muscle_kg=31.9,
        age=25
    )
    example_exercise_data = [
        ExerciseData(name="卧推", weight_kg=70, sets=5, reps=5)
    ]

    estimator.print_recovery_summary(example_exercise_data, example_body_data)

    print("\n" + "="*60)
    print("您也可以输入自己的数据进行估算：")

    try:
        height = float(input("请输入您的身高 (cm): "))
        weight = float(input("请输入您的体重 (kg): "))
        bf = float(input("请输入您的体脂率 (%): "))
        sm = float(input("请输入您的骨骼肌重量 (kg, 可选，输入0则使用默认估算): "))
        age = int(input("请输入您的年龄: "))

        if sm <= 0:
            # 简单估算骨骼肌重量 (仅供参考)
            # 此公式非常简化，仅用于演示
            lean_mass_kg = weight * (1 - bf / 100)
            estimated_sm = lean_mass_kg * 0.4 # 假设瘦体重的40%是骨骼肌
            print(f"估算的骨骼肌重量: {estimated_sm:.1f} kg (基于输入数据)")
            sm = estimated_sm

        user_body_data = BodyData(height, weight, bf, sm, age)

        exercises = []
        while True:
            name = input("\n请输入训练动作名称 (输入 'done' 结束): ").strip()
            if name.lower() == 'done':
                break
            try:
                weight_in = float(input(f"  - 重量 (kg): "))
                sets = int(input(f"  - 组数: "))
                reps = int(input(f"  - 次数: "))
                exercises.append(ExerciseData(name, weight_in, sets, reps))
            except ValueError:
                print("  输入错误，请重新输入该动作。")

        if exercises:
            print("\n--- 您的估算结果 ---")
            estimator.print_recovery_summary(exercises, user_body_data)
        else:
            print("未输入任何训练动作。")

    except ValueError:
        print("输入数据格式错误，程序结束。")
    except KeyboardInterrupt:
        print("\n程序被用户中断。")


if __name__ == "__main__":
    main()



